<template>

	<!-- 登录 -->
	<div class="login">
		<div class="login-box">
			<div class="head">
				<el-image :src="IMAGE_URL.headerUrl" class="header-image" fit="contain"></el-image>
			</div>
			<div class="form">
				<el-image :src="IMAGE_URL.logoSmallUrl" class="profile-avatar" fit="contain"></el-image>
				<div class="content">
					<div class="title-container">
						<h3 class="title">
							{{ $t('siteName') }}
						</h3>
					</div>
					<el-form ref="loginFormRef" :model="loginForm" :rules="loginRules" label-position="left">
						<el-form-item prop="username">
							<el-input
									ref="usernameRef"
									v-model="loginForm.username"
									:placeholder="$t('login.username')"
									:tabindex="1"
									autocomplete="on"
									class="cus-box-shadow"
									clearable
									name="username"
									type="text"
									@keyup.enter="usernameKeyUpEnter"
							>
								<template #prepend>
									<icon name="el-icon-User"/>
								</template>
							</el-input>
						</el-form-item>
						<el-form-item prop="password">
							<el-input
									ref="passwordRef"
									v-model="loginForm.password"
									:placeholder="$t('login.password')"
									autocomplete="on"
									class="cus-box-shadow"
									clearable
									name="password"
									show-password
									tabindex="2"
									type="password"
									@keyup.enter="handleLogin"
							>
								<template #prepend>
									<icon name="el-icon-Lock"/>
								</template>
							</el-input>
						</el-form-item>
						<div class="cus-center-column" style="margin-top: 20px">
							<el-button :loading="loading" style="width:100%;" type="primary" @click.prevent="handleLogin">
								{{ $t('login.login') }}
							</el-button>
							<el-button :loading="loading" style="width:100%;margin: 10px 0 0 0" type="primary"
							           @click.prevent="visitorLogin">
								{{ $t('login.loginWithGuest') }}
							</el-button>
							<el-button :loading="loading" style="width:100%;margin: 20px 0 0 0" type="primary"
							           @click.prevent="toRegister">
								{{ $t('login.register') }}
							</el-button>
							<div class="cus-center w100" style="margin-top: 20px">
								<el-link :underline="false" type="info" @click="toForgetPasswordPage">
									{{ $t('login.forgetPassword') }}
								</el-link>
							</div>
						</div>
					</el-form>
				</div>
			</div>
		</div>
	</div>

	<!-- 对话框（注册） -->
	<el-dialog v-model="dialogVisible" :close-on-click-modal="false" :close-on-press-escape="closeOnPressEscape" :title="$t('login.userRegistration')"
	           append-to-body center class="cus-dialog" destroy-on-close draggable width="30%">
		<el-form ref="registerFormRef" :model="registerForm" :rules="registerRules" label-width="auto">
			<el-form-item :label="$t('login.username')" prop="username">
				<el-input v-model="registerForm.username" :placeholder="$t('placeholder.username')" clearable></el-input>
			</el-form-item>
			<el-form-item :label="$t('login.nickname')" prop="nickname">
				<el-input v-model="registerForm.nickname" :placeholder="$t('placeholder.nickname')" clearable></el-input>
			</el-form-item>
			<el-form-item :label="$t('login.password')" prop="password">
				<el-input v-model="registerForm.password" :placeholder="$t('placeholder.password')" clearable show-password
				          type="password"></el-input>
			</el-form-item>
			<el-form-item :label="$t('login.passwordAgain')" prop="passwordAgain">
				<el-input v-model="registerForm.passwordAgain" clearable show-password type="password"
				></el-input>
			</el-form-item>
			<el-form-item :label="$t('login.gender')" prop="gender">
				<el-radio-group v-model="registerForm.gender">
					<el-radio :value="2" border>男</el-radio>
					<el-radio :value="3" border>女</el-radio>
					<el-radio :value="1" border>保密</el-radio>
				</el-radio-group>
			</el-form-item>
			<el-form-item :label="$t('login.email')" prop="email">
				<el-input v-model="registerForm.email" :placeholder="$t('placeholder.email')" clearable></el-input>
			</el-form-item>
			<el-form-item :label="$t('login.avatar')" prop="avatar">
				<el-upload
						ref="uploadRef"
						:auto-upload="false"
						:file-list="avatarFileList"
						:http-request="httpRequest"
						:on-change="fileListChanged"
						:on-error="onError"
						:on-preview="onImagePreview"
						:on-remove="fileRemoved"
						:on-success="onUploadSuccess"
						accept=".jpg,.jpeg,.png"
						drag
						list-type="picture-card"
				>
					<template #trigger>
						<em>点击或将文件拖拽至此处</em>
					</template>
					<template #tip>
						<div>
							支持 jpg/jpeg/png 格式，文件大小不超过 10MB
						</div>
					</template>
				</el-upload>
			</el-form-item>
			<el-form-item :label="$t('login.introduction')" prop="introduction">
				<el-input v-model="registerForm.introduction" :autosize="{ minRows: 4, maxRows: 4}"
				          :placeholder="$t('placeholder.optional')" clearable type="textarea"></el-input>
			</el-form-item>
		</el-form>
		<template #footer>
			<el-button icon="el-icon-CircleCheck" type="primary" @click="register">
				{{ $t('login.register') }}
			</el-button>
			<el-button icon="el-icon-CircleClose" type="warning" @click="dialogVisible = false">
				{{ $t('Cancel') }}
			</el-button>
		</template>
	</el-dialog>

	<!-- 头像大图预览 -->
	<el-image-viewer v-if="previewDialogVisible" :url-list="[previewImageUrl]" hide-on-click-modal @close="previewDialogVisible = false"/>

	<!-- 图片裁剪 -->
	<cropper
			ref="clipperRef"
			v-model:visible="cropperVisible"
			:allow-type-list="clipperData.allowTypeList"
			:fixed-number="clipperData.fixedNumber"
			:fixed-number-aider="clipperData.fixedNumberAider"
			:img="avatarImg"
			:limit-size="clipperData.limitSize"
			:preview-width="clipperData.previewWidth"
			:type="clipperData.type"
			file-name="avatar.png"
			title="头像裁剪"
			@cancel="onCropperCancel"
			@confirm="onCropperConfirm"/>

	<!-- 静音按钮 -->
	<div class="volume" @click="toggleMute">
		<icon :name="mute ? 'fa fa-volume-off' : 'fa fa-volume-up'" color="var(--el-text-color-secondary)" size="28"/>
	</div>

	<!-- 切换语言 -->
	<div class="switch-language">
		<el-dropdown :hide-on-click="true" :hide-timeout="50" placement="bottom-end" size="large">
			<icon color="var(--el-text-color-secondary)" name="local-cus-lang" size="28"/>
			<template #dropdown>
				<el-dropdown-menu>
					<el-dropdown-item v-for="item in webConfigStore.lang.langArray" :key="item.value" @click="loadLang(item.value)">
						{{ item.name }}
					</el-dropdown-item>
				</el-dropdown-menu>
			</template>
		</el-dropdown>
	</div>

	<!-- 背景图片和气泡效果 -->
	<!--	<div id="bubble" class="bubble" @contextmenu.stop="">-->
	<!--		<canvas id="bubble-canvas" class="bubble-canvas"></canvas>-->
	<!--	</div>-->

	<!-- 背景视频 -->
	<div class="homepage-hero-module">
		<div class="video-container">
			<video :muted="mute" :style="fixStyle" autoplay loop v-on:canplay="canplay">
				<source src="../../assets/video/satisfactory/login-bg-movie480.mp4" type="video/mp4"/>
				浏览器不支持 video 标签，建议升级浏览器。
			</video>
			<div v-if="!videoCanPlay" class="poster">
				<el-image :src=IMAGE_URL.moviePoster :style="fixStyle"></el-image>
			</div>
		</div>
	</div>

	<!-- 备案号 -->
	<icp></icp>

</template>

<script lang="ts" name="Login" setup>

import {nextTick, onBeforeUnmount, onMounted, reactive, ref, watch} from 'vue'
import {closeLoading, focusFormErrorElement, messageError, messageWarning, showLoading} from '@/utils/commonUtil'
import {validateUsername} from '@/utils/validateUtil'
import {useUserStore} from '@/stores/modules/user.store'
import {doRegisterApi} from '@/api/system/register.api'
import type {FormInstance, FormRules, InputInstance, UploadFile, UploadFiles, UploadInstance, UploadProps, UploadRawFile} from 'element-plus'
import {ElMessageBox} from 'element-plus'
import type {LocationQuery} from 'vue-router'
import router from '@/router'
import type {CusUploadRawFile, RuleItemValidator} from '@/model/global-import'
import Icon from '@/components/icon.vue'
import {useWebConfigStore} from '@/stores/modules/webConfig.store'
import {useI18n} from 'vue-i18n'
import {loadLang} from '@/lang'
import Icp from '@/components/icp.vue'
import {breakpointsAntDesign, useEventListener, useUrlSearchParams} from '@vueuse/core'
import {DEFAULT_USER, IMAGE_URL} from '@/utils/constantsUtil'
import {useOssStore} from '@/stores/modules/oss.store'
import Cropper from '@/components/cropper.vue'
import {isProd} from '@/utils/viteUtil'

const uploadRef = ref<UploadInstance>()

const {t} = useI18n()
const userStore = useUserStore()
const webConfigStore = useWebConfigStore()

const mute = ref(true)
const videoCanPlay = ref(false)
const canplay = () => {
	videoCanPlay.value = true
}
const fixStyle = ref()

const loading = ref(false)
const dialogVisible = ref(false)
const closeOnPressEscape = ref(true)
const registerForm = reactive<RegisterForm>({
	nickname: undefined,
	username: undefined,
	password: undefined,
	passwordAgain: undefined,
	email: undefined,
	avatar: undefined,
	gender: 1,
	introduction: undefined
})
const loginForm = reactive<LoginForm>({
	username: undefined,
	password: undefined
})
const loginRules = reactive<FormRules>({
	username: [
		{required: true, trigger: 'change', message: t('ruleMessage.username1')},
		{min: 2, max: 20, message: t('ruleMessage.username3'), trigger: 'change'}
	],
	password: [
		{required: true, trigger: 'change', message: t('ruleMessage.password1')},
		{min: 6, max: 50, message: t('ruleMessage.password2'), trigger: 'change'}
	]
})
const usernameValidator: RuleItemValidator = (rule, value, callback) => {
	if (validateUsername(value)) {
		callback()
	} else {
		callback(Error())
	}
}
const passwordAgainValidator: RuleItemValidator = (rule, value, callback) => {
	if (value === registerForm.password) {
		callback()
	} else {
		callback(Error())
	}
}
const registerRules = reactive<FormRules>({
	nickname: [
		{required: true, message: t('ruleMessage.nickname1'), trigger: 'change'},
		{min: 2, max: 20, message: t('ruleMessage.nickname2'), trigger: 'change'}
	],
	username: [
		{required: true, message: t('ruleMessage.username1'), trigger: 'change'},
		{message: t('ruleMessage.username2'), trigger: 'change', validator: usernameValidator}
	],
	password: [
		{required: true, message: t('ruleMessage.password1'), trigger: 'change'},
		{min: 6, max: 50, message: t('ruleMessage.password2'), trigger: 'change'}
	],
	passwordAgain: [
		{required: true, validator: passwordAgainValidator, message: t('ruleMessage.passwordAgain'), trigger: 'change'}
	],
	email: [
		{max: 320, message: t('ruleMessage.email1'), trigger: 'change'},
		{type: 'email', message: t('ruleMessage.email2'), trigger: 'change'}
	],
	gender: [
		{required: true, message: t('ruleMessage.gender'), trigger: 'change'}
	],
	introduction: [
		{required: false, max: 500, message: t('ruleMessage.introduction'), trigger: 'change'}
	]
})
const usernameRef = ref<InputInstance>()
const passwordRef = ref<InputInstance>()
const loginFormRef = ref<FormInstance>()
const registerFormRef = ref<FormInstance>()

const usernameKeyUpEnter = () => {
	passwordRef.value?.focus()
}

const toggleMute = () => {
	mute.value = !mute.value
}

const toForgetPasswordPage = () => {
	window.open(isProd(import.meta.env.MODE) ? 'https://www.my-satisfactory.cn/forgetPassword' : 'http://localhost:5173/forgetPassword', '_blank')
}

const handleLogin = () => {
	loginFormRef.value?.validate((isValid: boolean) => {
		if (isValid) {
			loading.value = true
			userStore.login(loginForm).then(() => {
				afterLogin()
			}).catch(() => {
				loading.value = false
			})
		} else {
			focusFormErrorElement()
		}
	})
}

const afterLogin = () => {
	// 登录后跳转的路由
	let loginToPath: string | undefined
	const query = useUrlSearchParams()
	// 把loginTo参数从路径参数中去掉，剩下的参数放入otherQuery
	const otherQuery: LocationQuery = {}
	for (const key in query) {
		if (key === 'loginTo') {
			const loginToQuery = query[key]
			if (Array.isArray(loginToQuery)) {
				loginToPath = loginToQuery[0] ?? undefined
			} else if (loginToQuery) {
				loginToPath = loginToQuery
			} else {
				loginToPath = undefined
			}
		} else {
			otherQuery[key] = query[key]
		}
	}
	// 如果loginTo中也含有路径参数，需要把这些参数加入到otherQuery中
	if (loginToPath && loginToPath.includes('?')) {
		const queryInLoginTo = new URLSearchParams(loginToPath.split('?')[1])
		loginToPath = loginToPath.split('?')[0]
		queryInLoginTo.forEach((value, key) => {
			otherQuery[key] = value
		})
	}
	// 有可能注销后换了用户登录，这时应该检查新登录的用户是否具有 loginToPath 路由的权限
	const allRoutes = router.getRoutes()
	if (loginToPath && allRoutes.some(value => value.path === loginToPath)) {
		router.push({path: loginToPath, query: otherQuery}).finally(() => {
			loading.value = false
		})
	} else {
		router.push({path: '/', query: otherQuery}).finally(() => {
			loading.value = false
		})
	}
}

const resetUser = () => {
	registerForm.nickname = undefined
	registerForm.username = undefined
	registerForm.password = undefined
	registerForm.passwordAgain = undefined
	registerForm.email = undefined
	registerForm.gender = 1
	registerForm.avatar = undefined
	registerForm.introduction = undefined
}

const visitorLogin = () => {
	loading.value = true
	userStore.login({
		username: DEFAULT_USER.VISITOR_USERNAME,
		password: DEFAULT_USER.VISITOR_PASSWORD
	}).then(() => {
		afterLogin()
	}).catch(() => {
		loading.value = false
	})
}

const toRegister = () => {
	resetUser()
	clearAvatarFiles()
	dialogVisible.value = true
}

const register = () => {
	registerFormRef.value?.validate(isValid => {
		if (isValid) {
			if (avatarFileList.value[0] && avatarFileList.value[0].status !== 'success') {
				// 上传头像，触发 httpRequest() 方法
				uploadRef.value?.submit()
			} else {
				// 不上传头像，直接注册
				doRegister()
			}
		} else {
			focusFormErrorElement()
		}
	})
}

const doRegister = () => {
	showLoading('正在注册新用户')
	doRegisterApi(registerForm).then(() => {
		let message = '注册成功'
		if (registerForm.email) {
			message += '，已向您的邮箱发送激活邮件，请注意查收'
		}
		ElMessageBox.alert(message, '注册成功', {
			confirmButtonText: '去登录',
			type: 'success',
			draggable: true
		}).finally(() => {
			loginForm.username = registerForm.username
			loginForm.password = undefined
			dialogVisible.value = false
			nextTick(() => {
				loginFormRef.value?.clearValidate()
				passwordRef.value?.focus()
			})
		})
	}).finally(() => {
		closeLoading()
	})
}

const videoSize = () => {
	const windowWidth = document.body.clientWidth
	const windowHeight = document.body.clientHeight
	const windowAspectRatio = windowHeight / windowWidth
	let videoWidth: number
	let videoHeight: number
	if (windowAspectRatio < 0.5625) {
		videoWidth = windowWidth
		videoHeight = videoWidth * 0.5625
		fixStyle.value = {
			height: windowWidth * 0.5625 + 'px',
			width: windowWidth + 'px',
			'margin-bottom': (windowHeight - videoHeight) / 2 + 'px',
			'margin-left': 'initial'
		}
	} else {
		videoHeight = windowHeight
		videoWidth = videoHeight / 0.5625
		fixStyle.value = {
			height: windowHeight + 'px',
			width: windowHeight / 0.5625 + 'px',
			'margin-left': (windowWidth - videoWidth) / 2 + 'px',
			'margin-bottom': 'initial'
		}
	}
	return videoSize
}

// 用户头像上传 - 开始

const ossStore = useOssStore()

const avatarFileList = ref<UploadFiles>([])
const avatarImg = ref('')
const cropperVisible = ref(false)
const clipperData = ref<IClipper>({
	type: '',
	allowTypeList: ['jpg', 'png'],
	limitSize: 1,
	fixedNumber: [1, 1],
	previewWidth: 0
})
const previewImageUrl = ref('')
const previewDialogVisible = ref(false)

watch(previewDialogVisible, value => {
	closeOnPressEscape.value = !value
})

/**
 * 文件状态改变时的钩子，添加文件、上传成功、上传失败时都会被调用
 */
const fileListChanged: UploadProps['onChange'] = (file, fileList) => {
	// 如果是上传成功后触发，则不再处理
	if (file.status === 'success') {
		return
	}
	// 校验文件格式和大小
	if (!file.name.endsWith('.jpg') && !file.name.endsWith('.jpeg') && !file.name.endsWith('.png') || file.size! / 1024 / 1024 > 10) {
		messageWarning('头像支持jpg/jpeg/png格式，大小不超过10m')
		fileList.pop()
		return
	}
	// 校验文件数量，替换后仅保留最后一次选择的文件
	if (fileList.length > 1) {
		fileList.splice(0, 1)
	}
	avatarFileList.value = fileList
	if (avatarFileList.value && avatarFileList.value.length > 0) {
		registerForm.avatar = avatarFileList.value[0].name
	} else {
		registerForm.avatar = undefined
	}
	registerFormRef.value?.validateField('avatar')
	// 打开图片剪裁对话框
	if (file.status === 'ready' && !(<CusUploadRawFile>file.raw)!.avatarCropped) {
		avatarImg.value = file.url!
		cropperVisible.value = true
	}
}

/**
 * 文件列表移除文件时的钩子
 */
const fileRemoved: UploadProps['onRemove'] = (file, fileList) => {
	avatarFileList.value = fileList
	if (avatarFileList.value && avatarFileList.value.length > 0) {
		registerForm.avatar = avatarFileList.value[0].name
	} else {
		registerForm.avatar = undefined
	}
	registerFormRef.value?.validateField('avatar')
}

const onImagePreview: UploadProps['onPreview'] = uploadFile => {
	previewImageUrl.value = uploadFile.url!
	previewDialogVisible.value = true
}

// 用于存储创建的对象URL，方便后续释放
const objectUrlToRevoke = ref<string>()

const onCropperConfirm = (file: File) => {
	avatarFileList.value[0].name = file.name
	avatarFileList.value[0].size = file.size

	const URL = window.URL || window.webkitURL
	// 如果之前有创建的URL，先释放
	if (objectUrlToRevoke.value) {
		URL.revokeObjectURL(objectUrlToRevoke.value)
	}

	// 创建新的URL
	const objectUrl = URL.createObjectURL(file)
	avatarFileList.value[0].url = objectUrl
	// 保存创建的URL以便后续释放
	objectUrlToRevoke.value = objectUrl

	const uploadRawFile: UploadRawFile = <UploadRawFile>file
	uploadRawFile.uid = avatarFileList.value[0].uid
	avatarFileList.value[0].raw = uploadRawFile
	const cusUploadRawFile: CusUploadRawFile = avatarFileList.value[0].raw!
	cusUploadRawFile.avatarCropped = true
	uploadRef.value?.handleStart(avatarFileList.value[0].raw!)
}

const onCropperCancel = () => {
	registerForm.avatar = undefined
	clearAvatarFiles()
	registerFormRef.value?.validateField('avatar')
}

const clearAvatarFiles = () => {
	avatarFileList.value = []
	uploadRef.value?.clearFiles()
}

/**
 * 覆盖默认的上传行为，可以自定义上传的实现
 * 文件上传并提交视频任务
 */
const httpRequest: UploadProps['httpRequest'] = async ({file}) => {
	showLoading('正在上传头像')
	// 检查ossClient是否初始化，没有则进行初始化
	await ossStore.initOssClient()
	// 定义唯一的文件名（含路径），示例：avatar/username/1672917110368/avatar.png
	const filePath = `avatar/${registerForm.username}/${new Date().getTime()}/${file.name}`
	const {res, name} = await ossStore.ossClient!.put(filePath, file)
	if (res.status === 200) {
		// name是oss上的文件存储路径，开头没有斜杠，不含bucket名称
		registerForm.avatar = name
		return Promise.resolve()
	} else {
		closeLoading()
		messageError('头像上传失败')
		return Promise.reject()
	}
}

/**
 * 文件上传成功时的钩子<br/>
 * 执行注册操作
 */
const onUploadSuccess = (response: any, uploadFile: UploadFile, uploadFiles: UploadFiles) => {
	doRegister()
}

/**
 * 文件上传失败时的钩子，处理httpRequest()方法内未捕获的异常
 */
const onError: UploadProps['onError'] = (err, file, fileList) => {
	closeLoading()
	messageError(err.message)
}

// 用户头像上传 - 结束

// import * as pageBubble from '@/utils/pageBubbleUtil'

onMounted(() => {
	if (userStore.logoutCallback) {
		userStore.logoutCallback()
		userStore.logoutCallback = undefined
	}
	// 气泡效果
	// pageBubble.init()
	// 输入框focus
	if (!loginForm.username) {
		usernameRef.value?.focus()
	} else if (!loginForm.password) {
		passwordRef.value?.focus()
	}
	useEventListener(window, 'resize', videoSize())
})

onBeforeUnmount(() => {
	// pageBubble.removeListeners()
	window.removeEventListener('resize', videoSize)
	// 在组件卸载前释放所有创建的对象URL
	if (objectUrlToRevoke.value) {
		const URL = window.URL || window.webkitURL
		URL.revokeObjectURL(objectUrlToRevoke.value)
		objectUrlToRevoke.value = undefined
	}
})

</script>

<style lang="scss" scoped>
.volume {
	cursor: pointer;
	position: fixed;
	right: 70px;
	top: 20px;
	z-index: 20;
}

.switch-language {
	cursor: pointer;
	position: fixed;
	right: 20px;
	top: 20px;
	z-index: 20;
}

.login {
	align-items: center;
	display: flex;
	height: 100vh;
	justify-content: center;
	position: absolute;
	top: 0;
	width: 100vw;
	z-index: 10;

	.login-box {
		background: var(--cus-bg-color-overlay);
		margin-bottom: 80px;
		overflow: hidden;
		padding: 0;
		width: 430px;
		box-shadow: 0 0 20px black;
	}

	.head {
		background: #ccccff;

		.header-image {
			display: block;
			margin: 0 auto;
			user-select: none;
			width: 430px;
			height: 201px;
			filter: brightness(80%);
		}
	}

	.form {
		position: relative;

		.profile-avatar {
			display: block;
			height: auto;
			left: calc(50% - 51px);
			position: absolute;
			top: -48px;
			user-select: none;
			width: 102px;
			z-index: 20;
		}

		.content {
			padding: 70px 40px 40px 40px;

			.title-container {
				position: relative;

				.title {
					font-size: 26px;
					font-weight: bold;
					margin: 0 auto 40px auto;
					text-align: center;
				}
			}
		}

		.submit-button {
			--el-button-bg-color: var(--el-color-primary);
			font-weight: 300;
			letter-spacing: 2px;
			margin-top: 15px;
			width: 100%;
		}
	}
}

@media screen and (max-width: 720px) {
	.login {
		align-items: center;
		display: flex;
		justify-content: center;

		.login-box {
			margin-top: 0;
			width: 340px;
		}
	}
}

@media screen and (max-height: 800px) {
	.login .login-box {
		margin-bottom: 0;
	}
}

//.bubble {
//	background: url(@/assets/image/login/bg.jpg) repeat;
//	overflow: hidden;
//}

@at-root .dark {
	.login {
		.login-box {
			background: #161b22;
		}

		.form {
			.submit-button {
				--el-button-bg-color: var(--el-color-primary-light-5);
				--el-button-border-color: rgba(240, 252, 241, 0.1);
			}
		}
	}

	//.bubble {
	//	background: url(@/assets/image/login/bg-dark.jpg) repeat;
	//}
}

.homepage-hero-module,
.video-container {
	position: relative;
	height: 100vh;
	overflow: hidden;
}

.video-container .poster,
.video-container video {
	z-index: 0;
	position: absolute;
	filter: brightness(60%);
	-webkit-filter: brightness(60%);
}

</style>
